package top.healthylife.basics.utils.exception;

import feign.FeignException;
import feign.codec.DecodeException;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.DefaultMessageSourceResolvable;
import org.springframework.validation.BindException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import top.healthylife.basics.utils.utils.R;

import java.util.stream.Collectors;

/**
 * 所有的异常服务使用中统一拦截进行统一返回处理，避免返回结果出现任何非正常的错误返回，此统一异常为服务端进行控制，还会在网关层进行再一次的处理，保证所有的结果返回统一化
 * 统一异常处理
 *
 * @author maoxiaomeng
 */
@Slf4j
@Data
@ControllerAdvice
@Configuration
@ResponseBody
@ConditionalOnMissingBean(UnifyExceptionHandler.class)
public class UnifyExceptionHandler {

    /**
     * 所有非正常结果的异常捕获，{@linkplain Exception} 此层异常数据会最严重的，说明业务中并未处理到此层业务的异常信息,需要在业务层或日志层面做业务异常通知
     *
     * @param e {@linkplain Exception} 异常类对象
     */
    @ExceptionHandler(value = Exception.class)
    public R<?> exceptionHandler(Exception e) {
        return R.failed(e.getMessage());
    }

    /**
     * 下游服务异常
     *
     * @param e 异常错误
     */
    @ExceptionHandler(value = FeignException.class)
    public R<?> exceptionHandler(FeignException e) {
        //直接打印堆栈信息
        log.error("服务异常", e);
        if (e.getCause() instanceof BusinessException) {
            BusinessException ex = (BusinessException) e.getCause();
            return businessExceptionExceptionHandler(ex);
        } else {
            //直接做为通用异常处理
            return exceptionHandler((Exception) e.getCause());
        }
    }

    @ExceptionHandler(value = DecodeException.class)
    public R<?> decodeHandler(FeignException e) {
        //直接打印堆栈信息
        log.error("服务异常", e);
        if (e.getCause() instanceof BusinessException) {
            BusinessException ex = (BusinessException) e.getCause();
            return businessExceptionExceptionHandler(ex);
        } else {
            //直接做为通用异常处理
            return exceptionHandler((Exception) e.getCause());
        }
    }

    /**
     * 系统业务异常可捕获错误异常与业务信息和系统信息，并记录
     */
    @ExceptionHandler(value = BusinessException.class)
    public R<?> businessExceptionExceptionHandler(BusinessException e) {
        return R.failed(e.getMessage());
    }

    /**
     * 请求参数完整性异常
     */
    @ResponseBody
    @ExceptionHandler(value = BindException.class)
    public R<?> bindExceptionHandler(BindException ex) {
        //直接打印堆栈信息
        log.error("请求入参不完整", ex);
        //获取网络信息
        String error = "请求入参不完整:具体如下" + ex.getBindingResult()
                .getAllErrors()
                .stream()
                .map(DefaultMessageSourceResolvable::getDefaultMessage)
                .collect(Collectors.joining("\r\n"));
        return R.failed(error);
    }

    /**
     * 请求参数完整性异常
     */
    @ResponseBody
    @ExceptionHandler(value = MethodArgumentNotValidException.class)
    public R<?> methodArgumentNotValidException(MethodArgumentNotValidException ex) {
        //直接打印堆栈信息
        log.error("请求入参不完整", ex);
        //获取网络信息
        String error = "请求入参不完整:具体如下" + ex.getBindingResult().getAllErrors().stream().map(DefaultMessageSourceResolvable::getDefaultMessage).collect(Collectors.joining("\r\n"));
        return R.failed(error);
    }


}
